// Author: Adwait Jog

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "zlib.h"

#include "../option_parser.h"
#include "shader.h"
#include "dram.h"
#include "mem_fetch.h"

#include "gpu-misc.h"
#include "delayqueue.h"
#include "dram.h"
#include "addrdec.h"
#include "l2cache.h"

class PWS_entry_t
{
public:
	int SW_stride;
	address_type end_addr;
	address_type pc;
	int wid;
	int counter;
	
	PWS_entry_t()
	{
		SW_stride = -1;
		end_addr = -1;
		pc = -1;
		wid = -1;
		counter = 0;
	}		
};
                                                      
class PWS_table_t
{
public:
	std::vector<PWS_entry_t> PWS_entries;	

	PWS_table_t()
	{
		PWS_entries.clear();	
	}
};


class IP_entry_t
{
public:
	
	int IW_stride;  //Stride Distance between misses
	int SW_stride;  //Stride Distance between misses
	address_type end_addr;
    address_type pc;
	int wid;
	int index;
	int counter;
	
	int row;
	int col;
	int bank, control, chip;
	
	
	IP_entry_t()
	{
		IW_stride = -1;
		SW_stride = -1;
		end_addr = -1;
		wid = -1;
		pc = -1;
		index = -1;
		counter = 0;
		
		row = -1;
		col = -1;
		bank  = -1;
		control =  -1;
		chip = -1;
	}	
	
};
										
class IP_table_t
{
public:
	std::vector<IP_entry_t> IP_entries;
	
	IP_table_t()
	{
		IP_entries.clear();	
	}
};

class GS_entry_t
{
public:
	
	int IW_stride;  //Stride Distance between misses
	int SW_stride;  //Stride Distance between misses
    address_type pc;
	int counter; 
	
	GS_entry_t()
	{
		IW_stride = -1;
		SW_stride = -1;
		pc = -1;
		counter = 1;
	}	
	
};
										
class GS_table_t
{
public:
	std::vector<GS_entry_t> GS_entries;
	
	GS_table_t()
	{
		GS_entries.clear();	
	}
};


class AD_entry_t
{
public:
	
	int IW_stride;  //Stride Distance between misses
	int SW_stride;  //Stride Distance between misses
    address_type pc;
	int counter; 
	
	int row;
	int col;
	int bank, control, chip;
	
	AD_entry_t()
	{
		IW_stride = -1;
		SW_stride = -1;
		pc = -1;
		counter = 1;
		row = -1;
		col = -1;
		bank  = -1;
		control =  -1;
		chip = -1;
	}	
	
};
										
class AD_table_t
{
public:
	std::vector<AD_entry_t> AD_entries;
	
	AD_table_t()
	{
		AD_entries.clear();	
	}
};

mem_fetch_t* prepare_prefetch_request(unsigned long long int addr, int bsize, 
						   int sid, int wid, enum mem_access_type mem_acc, address_type pc);			   
bool check_in_prefetch_queues(mem_fetch_t* mf, bool from_degree, unsigned long long int addr);
void * check_in_demand_waiting_queue(unsigned long long int addr, int sid);
void remove_from_sent_queue(unsigned long long int addr, int sid);

void l1_prefetcher_logic(unsigned long long int addr);
void l1_prefetcher_cleaner() ;

void printIPTable(int);
void printPWSTable(int);
void printGSTable(int);